/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "driver/gptimer/hpm6e00_gptimer.h"

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief 通用定时器获取通道默认配置
 *
 * \param[in] p_gptmr_reg 具体的定时器寄存器
 * \param[in] p_cfg       存储配置的缓存
 */
void gptmr_ch_default_cfg_get(hpm_gptmr_reg_t     *p_gptmr_reg,
                              struct gptmr_ch_cfg *p_cfg){

    if ((p_gptmr_reg == NULL) && (p_cfg == NULL)) {
        return;
    }

    p_cfg->mode              = gptmr_work_mode_no_capture;
    p_cfg->dma_request_event = gptmr_dma_request_disabled;
    p_cfg->synci_edge        = gptmr_synci_edge_none;

    for(uint8_t i = 0; i < GPTMR_CH_CMP_COUNT; i++) {
        p_cfg->cmp[i] = 0xFFFFFFFEUL;
    }
    p_cfg->reload                              = 0xFFFFFFFFUL;
    p_cfg->cmp_initial_polarity_high           = TRUE;
    p_cfg->enable_cmp_output                   = TRUE;
    p_cfg->enable_sync_follow_previous_channel = FALSE;
    p_cfg->enable_software_sync                = FALSE;
    p_cfg->debug_mode                          = TRUE;
}

/**
 * \brief 通用定时器通道初始化
 *
 * \param[in] p_gptmr_reg 具体的定时器寄存器
 * \param[in] ch_idx      定时器通道索引
 * \param[in] p_cfg       具体配置
 * \param[in] is_enable   是否使能
 *
 * \retval 成功返回 0
 */
int gptmr_ch_init(hpm_gptmr_reg_t     *p_gptmr_reg,
                  uint8_t              ch_idx,
                  struct gptmr_ch_cfg *p_cfg,
                  bool_t               is_enable){
    uint32_t v = 0;
    uint32_t tmp_value;

    if ((p_gptmr_reg == NULL) &&
            (p_cfg == NULL) &&
            (p_cfg->enable_sync_follow_previous_channel) &&
            (ch_idx == 0)) {
        return -EINVAL;
    }

    if (p_cfg->dma_request_event != gptmr_dma_request_disabled) {
        v |= (GPTMR_CHANNEL_CR_DMAEN_MASK | GPTMR_CHANNEL_CR_DMASEL_SET(p_cfg->dma_request_event));
    }
    v |= GPTMR_CHANNEL_CR_CAPMODE_SET(p_cfg->mode)
        | GPTMR_CHANNEL_CR_DBGPAUSE_SET(p_cfg->debug_mode)
        | GPTMR_CHANNEL_CR_SWSYNCIEN_SET(p_cfg->enable_software_sync)
        | GPTMR_CHANNEL_CR_CMPINIT_SET(p_cfg->cmp_initial_polarity_high)
        | GPTMR_CHANNEL_CR_SYNCFLW_SET(p_cfg->enable_sync_follow_previous_channel)
        | GPTMR_CHANNEL_CR_CMPEN_SET(p_cfg->enable_cmp_output)
        | GPTMR_CHANNEL_CR_CEN_SET(is_enable)
        | p_cfg->synci_edge;

    for (uint8_t i = 0; i < GPTMR_CH_CMP_COUNT; i++) {
        tmp_value = p_cfg->cmp[i - 1];
        if ((tmp_value > 0)  && (tmp_value != 0xFFFFFFFFu)) {
            tmp_value--;
        }
        WRITE_REG32(p_gptmr_reg->CHANNEL[ch_idx].CMP[i], GPTMR_CMP_CMP_SET(tmp_value));
    }
    tmp_value = p_cfg->reload;
    if ((tmp_value > 0) && (tmp_value != 0xFFFFFFFFu)) {
        tmp_value--;
    }

    WRITE_REG32(p_gptmr_reg->CHANNEL[ch_idx].RLD, GPTMR_CHANNEL_RLD_RLD_SET(tmp_value));
    WRITE_REG32(p_gptmr_reg->CHANNEL[ch_idx].CR, v);

    return 0;
}

/**
 * \brief 通用定时器通道反初始化
 *
 * \param[in] p_gptmr_reg 具体的定时器寄存器
 * \param[in] ch_idx      定时器通道索引
 *
 * \retval 成功返回 0
 */
int gptmr_ch_deinit(hpm_gptmr_reg_t *p_gptmr_reg,
                    uint8_t          ch_idx){
    if ((p_gptmr_reg == NULL) && (ch_idx == 0)) {
        return -EINVAL;
    }

    for (uint8_t i = 0; i < GPTMR_CH_CMP_COUNT; i++) {
        WRITE_REG32(p_gptmr_reg->CHANNEL[ch_idx].CMP[i], 0xFFFFFFFFUL);
    }

    WRITE_REG32(p_gptmr_reg->CHANNEL[ch_idx].RLD, 0xFFFFFFFFUL);
    WRITE_REG32(p_gptmr_reg->CHANNEL[ch_idx].CR, 0);

    return 0;
}

/**
 * \brief 检查通用定时器状态是否匹配状态掩码
 *
 * \param[in] p_gptmr_reg 具体的定时器寄存器
 * \param[in] status_mask 状态掩码
 *
 * \retval 匹配返回 0
 */
int gptmr_status_chk(hpm_gptmr_reg_t *p_gptmr_reg, uint32_t status_mask){
    if (p_gptmr_reg == NULL) {
        return -EINVAL;
    }

    if ((READ_REG32(p_gptmr_reg->SR) & status_mask) == status_mask) {
        return 0;
    }
    return -EDATA;
}

/**
 * \brief 清除通用定时器具体的状态
 *
 * \param[in] p_gptmr_reg 具体的定时器寄存器
 * \param[in] status_mask 要清除的状态
 *
 * \retval 成功返回 0
 */
int gptmr_status_clr(hpm_gptmr_reg_t *p_gptmr_reg, uint32_t status_mask){
    if (p_gptmr_reg == NULL) {
        return -EINVAL;
    }

    SET_REG32_BIT(p_gptmr_reg->SR, status_mask);

    return 0;
}

/**
 * \brief 通用定时器使能中断
 *
 * \param[in] p_gptmr_reg 具体的定时器寄存器
 * \param[in] irq_mask    要使能的中断
 *
 * \retval 成功返回 0
 */
int gptmr_irq_enable(hpm_gptmr_reg_t *p_gptmr_reg, uint32_t irq_mask){
    if (p_gptmr_reg == NULL) {
        return -EINVAL;
    }

    SET_REG32_BIT(p_gptmr_reg->IRQEN, irq_mask);

    return 0;
}

/**
 * \brief 通用定时器禁能中断
 *
 * \param[in] p_gptmr_reg 具体的定时器寄存器
 * \param[in] irq_mask    要禁能的中断
 *
 * \retval 成功返回 0
 */
int gptmr_irq_disable(hpm_gptmr_reg_t *p_gptmr_reg, uint32_t irq_mask){
    if (p_gptmr_reg == NULL) {
        return -EINVAL;
    }

    CLEAR_REG32_BIT(p_gptmr_reg->IRQEN, irq_mask);

    return 0;
}

/**
 * \brief 配置通道重载值
 *
 * \param[in] p_gptmr_reg 具体的定时器寄存器
 * \param[in] ch_idx      定时器通道索引
 * \param[in] reload      重载值
 *
 * \retval 成功返回 0
 */
int gptmr_ch_reload_cfg(hpm_gptmr_reg_t *p_gptmr_reg,
                         uint8_t          ch_idx,
                         uint32_t         reload){
    if ((p_gptmr_reg == NULL) || (ch_idx > 3)) {
        return -EINVAL;
    }

    WRITE_REG32(p_gptmr_reg->CHANNEL[ch_idx].RLD, GPTMR_CHANNEL_RLD_RLD_SET(reload));

    return 0;
}

/**
 * \brief 计数器启动
 *
 * \param[in] p_gptmr_reg 具体的定时器寄存器
 * \param[in] ch_idx      定时器通道索引
 *
 * \retval 成功返回 0
 */
int gptmr_counter_start(hpm_gptmr_reg_t *p_gptmr_reg, uint8_t ch_idx){
    if ((p_gptmr_reg == NULL) || (ch_idx > 3)) {
        return -EINVAL;
    }

    SET_REG32_BIT(p_gptmr_reg->CHANNEL[ch_idx].CR, GPTMR_CHANNEL_CR_CEN_MASK);

    return 0;
}

/**
 * \brief 计数器停止
 *
 * \param[in] p_gptmr_reg 具体的定时器寄存器
 * \param[in] ch_idx      定时器通道索引
 *
 * \retval 成功返回 0
 */
int gptmr_counter_stop(hpm_gptmr_reg_t *p_gptmr_reg, uint8_t ch_idx){
    if ((p_gptmr_reg == NULL) || (ch_idx > 3)) {
        return -EINVAL;
    }

    CLEAR_REG32_BIT(p_gptmr_reg->CHANNEL[ch_idx].CR, GPTMR_CHANNEL_CR_CEN_MASK);

    return 0;
}

/**
 * \brief 计数器值获取
 *
 * \param[in] p_gptmr_reg 具体的定时器寄存器
 * \param[in] ch_idx      定时器通道索引
 *
 * \retval 成功返回 计数器计数值
 */
uint32_t gptmr_counter_get(hpm_gptmr_reg_t *p_gptmr_reg, uint8_t ch_idx){
    if ((p_gptmr_reg == NULL) || (ch_idx > 3)) {
        return -EINVAL;
    }
    return READ_REG32(p_gptmr_reg->CHANNEL[ch_idx].CNT);
}



